﻿#include "dxstdafx.h"
#include "CStrategyTerrainRender.h"
#include "CStrategyRenderCommon.h"
#include "../CStrategyDefine.h"
#include "Data/DataMgr.h"
#include "Data/ProgramData/ProgramDataMgr.h"
#include "Data/ProgramData/StrategyMapData.h"

extern CStrategyRenderData g_StrategyRenderData;

CStrategyTerrainRender::CStrategyTerrainRender()
{
	m_pVBTerrainSquare = NULL;
	m_pIBTerrainSquare = NULL;
	m_dwTerrainSquareVerticesNum = 0;
	m_dwTerrainSquareIndicesNum = 0;
	m_pDecl = NULL;
	m_pEffect = NULL;
}

CStrategyTerrainRender::~CStrategyTerrainRender()
{
	SAFE_RELEASE(m_pVBTerrainSquare);
	SAFE_RELEASE(m_pIBTerrainSquare);
	SAFE_RELEASE(m_pDecl);
	SAFE_RELEASE(m_pEffect);
}

HRESULT CStrategyTerrainRender::OnCreateDevice(IDirect3DDevice9* pd3dDevice)
{
	HRESULT hr = S_OK;

	D3DVERTEXELEMENT9 decl[] =
	{
		{ 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
		{ 0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
		D3DDECL_END()
	};
	V_RETURN(pd3dDevice->CreateVertexDeclaration(decl, &m_pDecl));

	LPD3DXBUFFER pCode = NULL;
	std::wstring szRcPathOut;
	CommonFunc::RelativePath2FullPath(L"\\ResFile\\fx\\Strategy\\StrategyTerrainRender.fx", szRcPathOut);
	if (FAILED( hr = D3DXCreateEffectFromFile(pd3dDevice, szRcPathOut.c_str(), NULL, NULL,
		0, NULL, &m_pEffect, &pCode)))
	{
		LPVOID pBufErr = pCode->GetBufferPointer();
		char* ErrInfo = (char*)pBufErr;
		pCode->Release();
		return hr;
	}
	CommonFunc::CheckFxWarning(pCode);

	return hr;
}

HRESULT CStrategyTerrainRender::OnResetDevice(IDirect3DDevice9* pd3dDevice)
{
	HRESULT hr = S_OK;
	V_RETURN(CreateMeshWhenResetDevice(pd3dDevice));
 	V_RETURN(m_pEffect->SetTechnique("TerrainColor"));

	V_RETURN(m_pEffect->SetTexture("TerrainDiffuse", g_StrategyRenderData.m_pTexTerrainDiffuse));
	V_RETURN(m_pEffect->SetTexture("TerrainColorTint", g_StrategyRenderData.m_pTexTerrainColorTint));
 	V_RETURN(m_pEffect->SetTexture("HeightNormal", g_StrategyRenderData.m_pTexHeightNormal));
	V_RETURN(m_pEffect->SetTexture("TerrainNormal", g_StrategyRenderData.m_pTexTerrainNormal));
	V_RETURN(m_pEffect->SetTexture("TerrainIDMap", g_StrategyRenderData.m_pTexTerrainIDMap));

	V_RETURN(m_pEffect->SetVector("g_vMapSize_XZScale_YScale", &D3DXVECTOR4(c_nTerrainWidth, c_nTerrainHeight, c_fTerrainSqareScale, c_fHeightMapScale)));
	V_RETURN(m_pEffect->SetFloat("g_fSeaLevelHeight", c_nSeaLevelHeight * c_fHeightMapScale));
	return hr;
}

void CStrategyTerrainRender::OnFrameMove(const D3DXMATRIXA16* pWorldViewProject)
{
	HRESULT hr = S_OK;
	V(m_pEffect->SetMatrix("g_matWorldViewProject", pWorldViewProject));
}

void CStrategyTerrainRender::OnFrameRender(IDirect3DDevice9* pd3dDevice)
{
	// 远离屏幕就画 32 * 32 方格 再远继续少画 待完善
	HRESULT hr = S_OK;

	V(pd3dDevice->SetStreamSource(0, m_pVBTerrainSquare, 0, sizeof(_stStrategyTerrainD3DVertex)));
	V(pd3dDevice->SetVertexDeclaration(m_pDecl));
	V(pd3dDevice->SetIndices(m_pIBTerrainSquare));

	const BYTE* pHeightBuf = CDataMgr::Singleton().GetProgramDataMgrCPtr()->GetStrategyMapDataCPtr()->GetHeightBufCPtr();

	std::set<int> set_RenderSquare;
	if (!g_StrategyRenderData.UpdateRenderSquare(&set_RenderSquare))
	{
		return;
	}
	int  nSquareRowMax = 0, nSquareLineMax = 0;
	if (!g_StrategyRenderData.GetRenderAreaWH(&nSquareRowMax, &nSquareLineMax))
	{
		return;
	}
	
	int RenderSquareWidth = c_nTerrainSquareSize + 1;
	int nUseMultisample = (int)set_RenderSquare.size();

	for (const auto& iter : set_RenderSquare)
	{
		int SquareX = 0, SquareY = 0;
		CMathFunc::IndexTran2XY(&SquareX, &SquareY, iter, nSquareRowMax, nSquareLineMax);
		int nRowOffset = SquareX * c_nTerrainSquareSize;
		int nLineOffset = SquareY * c_nTerrainSquareSize;
		V(m_pEffect->SetVector("g_vQuadOffset_UseMultisample_Unused", &D3DXVECTOR4(nRowOffset, nLineOffset, nUseMultisample, 0.f)));

		// 设置高度
		_stStrategyTerrainD3DVertex *pVertices;
		V(m_pVBTerrainSquare->Lock(0, 0, (void**)&pVertices, 0));
		for (int iH = 0; iH <= c_nTerrainSquareSize; ++iH)
		{
			for (int jW = 0; jW <= c_nTerrainSquareSize; ++jW)
			{
				int indexVertex = CMathFunc::XYTran2Index(jW, iH, RenderSquareWidth, RenderSquareWidth);
				int indexHeight = CMathFunc::XYTran2Index(jW + nRowOffset, iH + nLineOffset, c_nTerrainWidth, c_nTerrainHeight);
				pVertices[indexVertex].height = pHeightBuf[indexHeight];
			}
		}
		V(m_pVBTerrainSquare->Unlock());

		UINT iPass, cPasses;
		V(m_pEffect->Begin(&cPasses, 0));
		for (iPass = 0; iPass < cPasses; ++iPass)
		{
			V(m_pEffect->BeginPass(iPass));
			V(pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, m_dwTerrainSquareVerticesNum, 0, m_dwTerrainSquareIndicesNum / 3));
			V(m_pEffect->EndPass());
		}
		V(m_pEffect->End());
	}
}

void CStrategyTerrainRender::OnLostDevice()
{
	if (m_pEffect)
	{
		m_pEffect->OnLostDevice();
	}
	SAFE_RELEASE(m_pVBTerrainSquare);
	SAFE_RELEASE(m_pIBTerrainSquare);
}

void CStrategyTerrainRender::OnDestroyDevice()
{
	SAFE_RELEASE(m_pVBTerrainSquare);
	SAFE_RELEASE(m_pIBTerrainSquare);
	SAFE_RELEASE(m_pEffect);
	SAFE_RELEASE(m_pDecl);
}

HRESULT CStrategyTerrainRender::CreateMeshWhenResetDevice(LPDIRECT3DDEVICE9 pd3dDevice)
{
	HRESULT hr = S_OK;

	int RenderSquareWidth = c_nTerrainSquareSize + 1;
	m_dwTerrainSquareVerticesNum = RenderSquareWidth * RenderSquareWidth;
	m_dwTerrainSquareIndicesNum = c_nTerrainSquareSize * c_nTerrainSquareSize * 6;
	
	// 生成 65 * 65 网格 左下角为( 0, 0 ) /_|
	{
		_stStrategyTerrainD3DVertex *pVertices;
		V_RETURN(pd3dDevice->CreateVertexBuffer(m_dwTerrainSquareVerticesNum * sizeof(_stStrategyTerrainD3DVertex),
			0, 0, D3DPOOL_DEFAULT, &m_pVBTerrainSquare, NULL));
		V_RETURN(m_pVBTerrainSquare->Lock(0, 0, (void**)&pVertices, 0));
		for (int iH = 0; iH < RenderSquareWidth; ++iH)
		{
			for (int jW = 0; jW < RenderSquareWidth; ++jW)
			{
				int index = iH * RenderSquareWidth + jW;
				pVertices[index].x = jW;
				pVertices[index].y = iH;
			}
		}
		V_RETURN(m_pVBTerrainSquare->Unlock());
	}
	{
		DWORD* pIndices;
		V_RETURN(pd3dDevice->CreateIndexBuffer(m_dwTerrainSquareIndicesNum * sizeof(DWORD),
			0, D3DFMT_INDEX32, D3DPOOL_DEFAULT, &m_pIBTerrainSquare, NULL));
		V_RETURN(m_pIBTerrainSquare->Lock(0, 0, (void**)&pIndices, 0));
		for (int iH = 0; iH < c_nTerrainSquareSize; ++iH)
		{
			for (int jW = 0; jW < c_nTerrainSquareSize; ++jW)
			{
				int index = (iH * c_nTerrainSquareSize + jW) * 6;
				pIndices[index] = iH * RenderSquareWidth + jW + 1;
				pIndices[index + 1] = pIndices[index] - 1;
				pIndices[index + 2] = pIndices[index] + RenderSquareWidth;
				pIndices[index + 3] = pIndices[index + 2];
				pIndices[index + 4] = pIndices[index + 1];
				pIndices[index + 5] = pIndices[index + 2] - 1;
			}
		}
		V_RETURN(m_pIBTerrainSquare->Unlock());
	}
	printf("Create Strategy Terrain Mesh Success!\n");
	return hr;
}